#include "usart_data_packet_analysis_app.h"

static uint8_t rcvDataBuf[MAX_BUF_SIZE]; // 创建数组 作为队列的数据缓冲区
static QueueStruct rcvQueue;             // 创建队列

/**
 * @desc  : 接收数据并保存到暂存区中
 * @date  : 2025-06-20
 * @author: AnRui
 * @param : data - {参数说明}: 数据指针
 * @param : len - {参数说明}:  数据长度
 * @note  : 检测数据的长度是否符合要求,并将符合要求的数据放到暂存区(队列)中
 */
void DataPacketGetData(uint8_t* data, uint32_t len) {
    if (len < PACKET_DATA_LEN_MIN || len > PACKET_DATA_LEN_MAX) return;
    QueuePushArr(&rcvQueue, data, len);
}


/**
 * @desc  : 对包数据进行异或校验
 * @date  : 2025-03-26
 * @author: AnRui
 * @param : data - {参数说明}:包数据指针
 * @param : len - {参数说明}: 包数据除了最后校验位的长度
 * @return: 是否符合校验 0:不符合 1:符合
 * @note  :  const uint8_t* data 避免内部代码 修改包数据
 */
static uint8_t CalXorSum(const uint8_t* data, uint32_t len) {
    uint8_t xorSum = 0;
    for (uint32_t i = 0; i < len; i++) {
        xorSum ^= data[i];
    }
    return xorSum;
}

/**
 * @desc  : 对缓冲区的包数据 校验并解析
 * @date  : 2025-03-26
 * @author: AnRui
 * @note  : 如果解析太快了 获取到第1位数据时   第二位数据还没有到 这个时候就会失败 这个包的数据就不会被解析了？
 *          为了避免解析过快 加上 rcvQueue.curNum >= PACKET_DATA_LEN_MIN 保证至少有一个完整的包数据 才会解析
 *          那么会不会导致包解析的慢呢? 应该会的 所以要考虑 解析数据的频率 这个比较要不要加 也看实际情况
 */
void DataPacketProtocolAnalysis(void) {
    uint8_t tmpDataBuff[PACKET_DATA_LEN_MAX] = { 0 };
    QueueStatusEnum result = QUEUE_OK;
    // 当队列中保存最小长度的包数据时 才进行解析
    while (rcvQueue.curNum >= PACKET_DATA_LEN_MIN) {
        // 先取出3个数据 帧头1 帧头2 数据长度 
        result = QueuePopArr(&rcvQueue, &tmpDataBuff[0], 3);
        // 检测帧头0 帧头1 是否符合协议
        if (result != QUEUE_OK) continue;
        if ((tmpDataBuff[0] != FRAME_HEAD_0) || (tmpDataBuff[1] != FRAME_HEAD_1)) continue;

        //取出该包的剩余数据 剩余数据的长度等于数据位数+1位校验位
        result = QueuePopArr(&rcvQueue, &tmpDataBuff[3], tmpDataBuff[2] + 1);
        if (result != QUEUE_OK) continue;

        //异或校验
        if (CalXorSum(tmpDataBuff, tmpDataBuff[2] + 3) != tmpDataBuff[tmpDataBuff[2] + 3]) {
            continue;
        }

        // 验证通过后  根据功能码执行对应的操作
        switch (tmpDataBuff[FUNC_DATA_IDX]) {
        case 0x06:
            // lcd处理
            printf("lcd do \r\n");
            break;
        default:
            break;
        }
    }
}


/**
 * @desc  : 协议解析初始化
 * @date  : 2025-03-26
 * @author: AnRui
 * @note  : 在usart中注册自己的数据接收函数
 *          当usart接收到数据时 会把数据放到自己的队列中,为接下来解析做准备
 */
void DataPacketProtocolAnalysisInit(void) {
    QueueInit(&rcvQueue, rcvDataBuf, MAX_BUF_SIZE);
}

